package fun.qu_an.minecraft.mini_games_helper.client.mixin.sodium;

import fun.qu_an.minecraft.mini_games_helper.client.handle.ForceOptionHelperSodium;
import fun.qu_an.minecraft.mini_games_helper.client.handle.ForceOptionHelperVanilla;
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptionPages;
import me.jellysquid.mods.sodium.client.gui.options.Option;
import me.jellysquid.mods.sodium.client.gui.options.OptionImpl;
import me.jellysquid.mods.sodium.client.gui.options.OptionPage;
import me.jellysquid.mods.sodium.client.gui.options.binding.GenericBinding;
import me.jellysquid.mods.sodium.client.gui.options.binding.OptionBinding;
import me.jellysquid.mods.sodium.client.gui.options.binding.compat.VanillaBooleanOptionBinding;
import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl;
import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage;
import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage;
import me.jellysquid.mods.sodium.client.gui.options.storage.SodiumOptionsStorage;
import net.irisshaders.iris.pathways.colorspace.ColorSpace;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.client.option.SimpleOption;
import net.minecraft.text.*;
import net.minecraft.util.Formatting;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Optional;

@Mixin(SodiumGameOptionPages.class)
public class SodiumGameOptionPagesMixin {
	@Shadow(remap = false)
	@Final
	private static MinecraftOptionsStorage vanillaOpts;
	@Shadow(remap = false)
	@Final
	private static SodiumOptionsStorage sodiumOpts;

	@Inject(remap = false, method = "general",
		at = @At(value = "RETURN", target = "Lcom/google/common/collect/ImmutableList;copyOf(Ljava/util/Collection;)Lcom/google/common/collect/ImmutableList;"))
	private static void general(CallbackInfoReturnable<OptionPage> cir) {
		cir.getReturnValue().getOptions().forEach(SodiumGameOptionPagesMixin::mgh$execute);
	}

	@Inject(remap = false, method = "quality",
		at = @At(value = "RETURN", target = "Lcom/google/common/collect/ImmutableList;copyOf(Ljava/util/Collection;)Lcom/google/common/collect/ImmutableList;"))
	private static void quality(CallbackInfoReturnable<OptionPage> cir) {
		cir.getReturnValue().getOptions().forEach(SodiumGameOptionPagesMixin::mgh$execute);
	}

	@Inject(remap = false, method = "performance",
		at = @At(value = "RETURN", target = "Lcom/google/common/collect/ImmutableList;copyOf(Ljava/util/Collection;)Lcom/google/common/collect/ImmutableList;"))
	private static void performance(CallbackInfoReturnable<OptionPage> cir) {
		cir.getReturnValue().getOptions().forEach(SodiumGameOptionPagesMixin::mgh$execute);
	}

	@Inject(remap = false, method = "advanced",
		at = @At(value = "RETURN", target = "Lcom/google/common/collect/ImmutableList;copyOf(Ljava/util/Collection;)Lcom/google/common/collect/ImmutableList;"))
	private static void advanced(CallbackInfoReturnable<OptionPage> cir) {
		cir.getReturnValue().getOptions().forEach(SodiumGameOptionPagesMixin::mgh$execute);
	}

	@Unique
	@SuppressWarnings("unchecked")
	private static void mgh$execute(Option<?> o) {
		OptionImpl<OptionStorage<?>, ?> option = (OptionImpl<OptionStorage<?>, ?>) o;
		String key = ((TranslatableTextContent) option.getName().getContent()).getKey();
		OptionImplAccessor optionImplAccessor = (OptionImplAccessor) option;
		if (option.getStorage().equals(vanillaOpts)) {

			// iris

			if (key.equals("options.iris.colorSpace")) { // 另一个是 options.iris.shadowDistance
				OptionImpl<OptionStorage<?>, ColorSpace> option1 = (OptionImpl<OptionStorage<?>, ColorSpace>) option;
				if (!(option1.getControl() instanceof CyclingControl<?> c)) {
					return;
				}

				ClientPlayerInteractionManager interactionManager = MinecraftClient.getInstance().interactionManager;
				if (interactionManager == null) {
					return;
				}

				Optional<ColorSpace> forcedColorSpace = ForceOptionHelperSodium.getColorSpace(interactionManager.getCurrentGameMode());
				if (forcedColorSpace.isEmpty()) {
					return;
				}

				CyclingControl<ColorSpace> control = (CyclingControl<ColorSpace>) c;
				CyclingControlAccessor<ColorSpace> controlAccessor = (CyclingControlAccessor<ColorSpace>) control;
				controlAccessor.setAllowedValues(new ColorSpace[]{forcedColorSpace.get()});
				OptionImplAccessor optAccessor = (OptionImplAccessor) option;
				optAccessor.setBinding(new GenericBinding<OptionStorage<?>, ColorSpace>((a, b) -> {
				}, (a) -> forcedColorSpace.get()));
				optionImplAccessor.setAvailable(false);
				optionImplAccessor.setTooltip(optionImplAccessor.getTooltip().copy()
					.append(Text.of("\n"))
					.append(Text.literal("* Locked by server. *").setStyle(Style.EMPTY.withColor(Formatting.DARK_RED))));
				return;
			}

			// vanilla

			SimpleOption<Object> forcedOption = ForceOptionHelperVanilla.getForced(key);
			if (forcedOption == null) {
				return;
			}
			// ignore setters
			OptionBinding<?, ?> binding = optionImplAccessor.getBinding();
			if (binding instanceof GenericBinding<?, ?> genericBinding) {
				((GenericBindingAccessor) genericBinding).setSetter((a, b) -> {
				});
			} else if (binding instanceof VanillaBooleanOptionBinding) {
				optionImplAccessor.setBinding(new VanillaBooleanOptionBinding(SimpleOption.ofBoolean(key, (Boolean) forcedOption.value)));
			} else {
				throw new AssertionError();
			}

			return;
		}

		// sodium

		if (!option.getStorage().equals(sodiumOpts)) {
			return;
		}
	}
}
